package components

// A component that doubles its inputs
type doubler struct {
	Input  <-chan int
	Output chan<- int
}

type doubleOnce struct {
	In  <-chan int
	Out chan<- int
}

type adder struct {
	Op1 <-chan int
	Op2 <-chan int
	Sum chan<- int
}

type echo struct {
	In  <-chan int
	Out chan<- int
}

func (e *echo) Process() {
	for i := range e.In {
		e.Out <- i
	}
}

func (d *doubler) Process() {
	for i := range d.Input {
		d.Output <- i * 2
	}
}

func (d *doubleOnce) Process() {
	i := <-d.In
	d.Out <- i * 2
}

func (a *adder) Process() {
	op1Buf := make([]int, 0, 10)
	op2Buf := make([]int, 0, 10)
	addOp := func(op int, buf, otherBuf *[]int) {
		if len(*otherBuf) > 0 {
			otherOp := (*otherBuf)[0]
			*otherBuf = (*otherBuf)[1:]
			a.Sum <- op + otherOp
		} else {
			*buf = append(*buf, op)
		}
	}
	for a.Op1 != nil || a.Op2 != nil {
		select {
		case op1, ok := <-a.Op1:
			if !ok {
				a.Op1 = nil
				break
			}
			addOp(op1, &op1Buf, &op2Buf)
		case op2, ok := <-a.Op2:
			if !ok {
				a.Op2 = nil
				break
			}
			addOp(op2, &op2Buf, &op1Buf)
		}
	}
}
